import Foundation
import CoreTelephony
import Network
import AdSupport
import AppTrackingTransparency
import Darwin.Mach
import CoreTelephony
import Reachability
import UIKit

import FBSDKCoreKit
import SystemConfiguration.CaptiveNetwork
class LDeviceTool{
    static let info = DeviceInfo()
     
//    static func idfa() async -> String {
//            return await info.getIDFA() 
//    }
    
 
    static func idfv() -> String {
        // 尝试从钥匙串中获取IDFV
        if let storedIDFV = KeychainService.getIDFV() {
            return storedIDFV
        } else {
            // 生成新的IDFV并保存到钥匙串中
            let newIDFV = UUID().uuidString
            KeychainService.saveIDFV(newIDFV)
            return newIDFV
        }
    }
    
    static private var _appName:String?
    static var appName : String {
        if _appName == nil {
            if let displayName = Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String {
                _appName = displayName
            } else if let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String {
                _appName = appName
            } else {
            }
        }
        return _appName ?? ""
    }
    
    static var appVersion : String {info.appVersion()}
    
    static var networkName :  String {info.getNetworkName()}
    
    static var totalDisk : String { info.totalDisk()}
    static var freeDisk :Int64 { info.freeDisk()}
    
    static var totalMemory : String { info.totalMemory() }
    static var freeMemory : String { info.freeMemory() }
    
    static var batteryState : String { info.batteryState() }
    static var modelName : String { info.modelName() }
    
    static var batteryPower : Int {info.getBatteryPercentage()}
    static var iOSVersion : String { UIDevice.current.systemVersion}
    
    static var rAMSize : String {info.getRAMSizeAsString()}
    static var deviceH : String { info.deviceH() }
    static var deviceW : String { info.deviceW() }
    static var deviceWXH : String { info.deviceWXH() }
    static var deviceDiagonal : String { info.deviceDiagonal() }
    static var timeZone : String { info.timeZone() }
    static var isSimulator : Bool { TARGET_OS_SIMULATOR != 0 }
    static var isBroken : Bool { info.isBroken() }
    static var isNetProxy : Bool { info.isNetProxy() }
    static var isVPN : Bool { info.isVPN() }
    
    static var carrierName : String { info.getCarrierName() }
    static var systemLanguage : String { info.getSystemLanguage() }
//    static var ipAddress : String { AppDeviceMacro.netWorkIP()}
        static var ipAddress : String { IPAddressManager.getLocalIPAddress() }
    static  func getDeviceInfo()   -> Dictionary<String,Any?> {
        var dict = [String : AnyObject]()
        dict["insided".rhx] = ["rap".rhx:freeDisk,
                              "catch".rhx:totalDisk,
                              "commissioned".rhx:rAMSize,
                              "interviews".rhx:freeMemory
        ]as AnyObject?
        dict["podcast".rhx] = ["koink".rhx:batteryPower,
                                     "spelling".rhx:batteryState,
                                     "geoff".rhx:(batteryState=="Charging") ? 1 : 0
        ]as AnyObject?
        dict["presented".rhx] = ["official".rhx:iOSVersion,
                               "whiskies".rhx:"iPhone",//--设备名牌
                               "diageo".rhx:modelName,
                               "hold".rhx:deviceH,
                               "injured".rhx:deviceW,
                               "represented".rhx:deviceDiagonal,
                               "buckskins".rhx:deviceWXH,//物理尺寸，屏幕对角线尺寸，单位英寸
                               "scene".rhx:""//----出厂时间戳
        ]as AnyObject?
        
        
        dict["picture".rhx]=[]as AnyObject
        dict["historical".rhx]=["grand".rhx:"0",
                               "artist".rhx:isSimulator ? 1 : 0,
                               "clever".rhx:isBroken ? 1 : 0
        ]as AnyObject
        dict["starting".rhx]=["americas".rhx:timeZone,
                                 "ornamental".rhx:isNetProxy ? 1 : 0,
                                 "wore".rhx:isVPN ? 1 : 0,
                                 "visited".rhx:carrierName,
                                 "andy".rhx:idfv(),
                                 "admired".rhx:systemLanguage,
                                 "traveling".rhx:networkName,
                                 "tips".rhx:1,//------指示设备电话类型的常量1 手机;2 平板
                                 "resin".rhx:ipAddress,
                                 "hosts".rhx:  info.idfa()
        ]as AnyObject
        
        let conferring=WiFiManager.fetchWiFiList()
        var wifiList: [String: Any?] = [:] 
        if wifiList.isEmpty{
            for   item in conferring {
                wifiList = [
                    "ulysse".rhx:item["BSSID"],
                    "apparel".rhx:item["BSSID"],
                    "invaded".rhx:item["SSID"],
                    "ommegang".rhx:item["SSID"]
                ]
            }
        }
        
        let curWifoDic = WiFiManager.currentWiFiInfo()
        var curWifo :Dictionary<String,Any?> = [:]
        if curWifoDic?["BSSID"] != nil {
              curWifo = [
                "ulysse".rhx:curWifoDic?["BSSID"],
                "apparel".rhx:curWifoDic?["BSSID"],
                "invaded".rhx:curWifoDic?["SSID"],
                "ommegang".rhx:curWifoDic?["SSID"]
            ]
        }
        dict["wristwatch".rhx] = ["nardin".rhx:wifiList]  as AnyObject
       
        dict["boys".rhx]=["astonished".rhx:curWifo,
                            "taller".rhx:wifiList.count,
                            "extreme".rhx:wifiList]
        as AnyObject
        
        
        return dict
    }
}

class DeviceInfo{
//    func getIDFA() async -> String {
//        
//        if #available(iOS 14, *) {
//            let status = await ATTrackingManager.requestTrackingAuthorization()
//            switch status {
//            case .authorized,.denied,.restricted:
//                
//                 return idfa()
//            case .notDetermined:
//                Thread.sleep(forTimeInterval: 1)
//                return await getIDFA()
//                
//            @unknown default: //.notDetermined
//                return  idfa()
//                
//            }
//        } else {
//            return  idfa()
//        }
//    }
    
    func idfa() ->String {
        let idfa =   ASIdentifierManager.shared().advertisingIdentifier.uuidString
        return idfa
    }
    func appVersion() ->String {
        if let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
            return appVersion
        } else {
            return "error"
        }
        
    }
    
    func getNetworkName() -> String {
        let reachability = try! Reachability()
        
        if reachability.connection == .wifi {
            return "WiFi"
        } else if reachability.connection == .cellular {
            let networkInfo = CTTelephonyNetworkInfo()
            if let currentRadioTechnology = networkInfo.currentRadioAccessTechnology {
                if #available(iOS 14.1, *) {
                    switch currentRadioTechnology {
                    case CTRadioAccessTechnologyGPRS,
                         CTRadioAccessTechnologyEdge,
                         CTRadioAccessTechnologyCDMA1x:
                        return "2G"
                    case CTRadioAccessTechnologyWCDMA,
                         CTRadioAccessTechnologyHSDPA,
                         CTRadioAccessTechnologyHSUPA,
                         CTRadioAccessTechnologyCDMAEVDORev0,
                         CTRadioAccessTechnologyCDMAEVDORevA,
                         CTRadioAccessTechnologyCDMAEVDORevB,
                         CTRadioAccessTechnologyeHRPD:
                        return "3G"
                    case CTRadioAccessTechnologyLTE:
                        return "4G"
                    case CTRadioAccessTechnologyNR:
                        return "5G"
                    default:
                        return "Cellular"
                    }
                } else {
                    // Handle iOS versions prior to iOS 14.1
                    // Return appropriate value based on available radio technologies
                    // For example:
                    return "Cellular"
                }
            }
        }
        
        return "Unknown"
    }
    
    func totalDisk() -> String {
        do {
            let attrs = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory())
            guard let space = attrs[FileAttributeKey.systemSize] as? NSNumber else {
                return "-1"
            }
            let diskSpace = space.int64Value
            if diskSpace < 0 {
                return "-1"
            }
            return "\(diskSpace)"
        } catch {
            return "-1"
        }
    }
    func freeDisk() -> Int64 {
        do {
            let url = URL(fileURLWithPath: NSTemporaryDirectory())
            let results = try url.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey])
            if let freeSpace = results.volumeAvailableCapacityForImportantUsage {
                return freeSpace
            } else {
                return -1
            }
        } catch {
            return -1
        }
    }
    func totalMemory() -> String {
        let totalMemory = ProcessInfo.processInfo.physicalMemory
        if Int64(totalMemory) < -1 {
            return "-1"
        }
        return "\(totalMemory)"
    }
    

  
    func freeMemory() -> String {
        var size = mach_msg_type_number_t(MemoryLayout<vm_statistics64_data_t>.size / MemoryLayout<integer_t>.size)
        var vmStat = vm_statistics64()
        var pageSize: vm_size_t = 0
        
        let hostPort: mach_port_t = mach_host_self()
        host_page_size(hostPort, &pageSize)
        
        let status = withUnsafeMutablePointer(to: &vmStat) {
            $0.withMemoryRebound(to: integer_t.self, capacity: Int(size)) {
                host_statistics64(hostPort, HOST_VM_INFO64, $0, &size)
            }
        }
        
        if status == KERN_SUCCESS {
            // Calculate free memory using the specified formula
            let freeMemory = (
                UInt64(vmStat.free_count) +
                UInt64(vmStat.inactive_count) +
                UInt64(vmStat.external_page_count) +
                UInt64(vmStat.purgeable_count) -
                UInt64(vmStat.speculative_count)
            ) * UInt64(pageSize)
            
            return "\(freeMemory)"
        } else {
            print("Failed to fetch vm statistics: \(status)")
            return "Error"
        }
    }
    
    func getRAMSizeAsString() -> String {
        let processInfo = ProcessInfo.processInfo
        let ramSizeInBytes = processInfo.physicalMemory
        return "\(ramSizeInBytes)"
    }

      
    
    func getBatteryPercentage() -> Int {
        UIDevice.current.isBatteryMonitoringEnabled = true
        let batteryLevel = UIDevice.current.batteryLevel
        
        if batteryLevel == -1 {
            return -1 // 未知电量
        }
        
        let batteryPercentage = Int(batteryLevel * 100)
        return batteryPercentage
    }
    func batteryState() -> String {
        UIDevice.current.isBatteryMonitoringEnabled = true
        switch UIDevice.current.batteryState {
        case .charging:
            if UIDevice.current.batteryLevel == 1 {
                return "Fully charged"
            } else {
                return "Charging"
            }
        case .full:
            return "Fully charged"
        case .unplugged:
            return "Unplugged"
        default:
            return "Unknown"
        }
    }
    func modelName() -> String {
        var systemInfo = utsname()
        uname(&systemInfo)
        let machine = withUnsafePointer(to: &systemInfo.machine) {
            $0.withMemoryRebound(to: CChar.self, capacity: 1) {
                String(cString: $0)
            }
        }
        
        let machineString = String(validatingUTF8: machine) ?? ""
        
        switch machineString {
        case "iPhone7,2":
            return "iPhone6"
        case "iPhone7,1":
            return "iPhone6Plus"
        case "iPhone8,1":
            return "iPhone6s"
        case "iPhone8,2":
            return "iPhone6sPlus"
        case "iPhone8,4", "iPhone12,8", "iPhone14,6":
            return "iPhoneSE"
        case "iPhone9,1", "iPhone9,3":
            return "iPhone7"
        case "iPhone9,2", "iPhone9,4":
            return "iPhone7Plus"
        case "iPhone10,1", "iPhone10,4":
            return "iPhone8"
        case "iPhone10,2", "iPhone10,5":
            return "iPhone8Plus"
        case "iPhone10,3", "iPhone10,6":
            return "iPhoneX"
        case "iPhone11,8":
            return "iPhoneXR"
        case "iPhone11,2":
            return "iPhoneXS"
        case "iPhone11,4", "iPhone11,6":
            return "iPhoneXS_MAX"
        case "iPhone12,1":
            return "iPhone11"
        case "iPhone12,3":
            return "iPhone11Pro"
        case "iPhone12,5":
            return "iPhone11ProMax"
        case "iPhone13,1":
            return "iPhone12Mini"
        case "iPhone13,2":
            return "iPhone12"
        case "iPhone13,3":
            return "iPhone12Pro"
        case "iPhone13,4":
            return "iPhone12ProMax"
        case "iPhone14,4":
            return "iPhone13Mini"
        case "iPhone14,5":
            return "iPhone13"
        case "iPhone14,2":
            return "iPhone13Pro"
        case "iPhone14,3":
            return "iPhone13ProMax"
        case "iPhone14,7":
            return "iPhone14"
        case "iPhone14,8":
            return "iPhone14Plus"
        case "iPhone15,2":
            return "iPhone14Pro"
        case "iPhone15,3":
            return "iPhone14ProMax"
        case "i386", "x86_64":
            return "Simulator"
        default:
            return machineString
        }
    }
    func deviceH() -> String {
        let screen = UIScreen.main
        let height = screen.bounds.size.height * screen.scale
        return String(format: "%.f", height)
    }
    
    func deviceW() -> String {
        let screen = UIScreen.main
        let width = screen.bounds.size.width * screen.scale
        return String(format: "%.f", width)
    }
    
    func deviceWXH() -> String {
        let screen = UIScreen.main
        let width = screen.bounds.size.width
        let height = screen.bounds.size.height
        return String(format: "%.fX%.f", width, height)
    }
    func deviceDiagonal() -> String {
        let deviceModel = modelName()
        
        if deviceModel == "iPhoneSE" {
            return "4"
        } else if deviceModel == "iPhone6" || deviceModel == "iPhone6s" || deviceModel == "iPhone7" || deviceModel == "iPhone8" || deviceModel == "iPhoneSE2nd" {
            return "4.7"
        } else if deviceModel == "iPhone12Mini" || deviceModel == "iPhone13Mini" {
            return "5.4"
        } else if deviceModel == "iPhone6Plus" || deviceModel == "iPhone6sPlus" || deviceModel == "iPhone7Plus" || deviceModel == "iPhone8Plus" {
            return "5.5"
        } else if deviceModel == "iPhoneX" || deviceModel == "iPhoneXS" || deviceModel == "iPhone11Pro" {
            return "5.8"
        } else if deviceModel == "iPhoneXR" || deviceModel == "iPhone11" || deviceModel == "iPhone12" || deviceModel == "iPhone12Pro" || deviceModel == "iPhone13" || deviceModel == "iPhone13Pro" || deviceModel == "iPhone14" || deviceModel == "iPhone14Pro" {
            return "6.1"
        } else if deviceModel == "iPhoneXS_MAX" || deviceModel == "iPhone11ProMax" {
            return "6.5"
        } else if deviceModel == "iPhone12ProMax" || deviceModel == "iPhone13ProMax" || deviceModel == "iPhone14Plus" || deviceModel == "iPhone14ProMax" {
            return "6.7"
        } else {
            let scale = UIScreen.main.scale
            let ppi = scale * (UIDevice.current.userInterfaceIdiom == .pad ? 132 : 163)
            let width = UIScreen.main.bounds.size.width * scale
            let height = UIScreen.main.bounds.size.height * scale
            let horizontal = width / ppi
            let vertical = height / ppi
            let diagonal = sqrt(pow(horizontal, 2) + pow(vertical, 2))
            return String(format: "%.1f", diagonal)
        }
    }
    func isBroken() -> Bool {
        let jailPaths = [
            "/Applications/Cydia.app",
            "/Library/MobileSubstrate/MobileSubstrate.dylib",
            "/bin/bash",
            "/usr/sbin/sshd",
            "/etc/apt"
        ]
        
        for path in jailPaths {
            if FileManager.default.fileExists(atPath: path) {
                return true
            }
        }
        
        return false
    }
    func timeZone() -> String {
        NSTimeZone.resetSystemTimeZone()
        return TimeZone.current.identifier
    }
    func isNetProxy() -> Bool {
        guard let proxySettings = CFNetworkCopySystemProxySettings()?.takeRetainedValue() as NSDictionary?,
              let proxies = CFNetworkCopyProxiesForURL(URL(string: "http://www.baidu.com")! as CFURL, proxySettings).takeRetainedValue() as NSArray?,
              let settings = proxies.firstObject as? NSDictionary,
              let proxyType = settings[kCFProxyTypeKey] as? String else {
            return false
        }
        
        if proxyType == kCFProxyTypeNone as String {
            return false
        } else {
            return true
        }
    }
    func isVPN() -> Bool {
        if let dict = CFNetworkCopySystemProxySettings()?.takeRetainedValue() as NSDictionary?,
           let scopedDict = dict["__SCOPED__"] as? NSDictionary,
           let keys = scopedDict.allKeys as? [String] {
            for key in keys {
                if key.range(of: "tap") != nil ||
                    key.range(of: "tun") != nil ||
                    key.range(of: "ipsec") != nil ||
                    key.range(of: "ppp") != nil {
                    return true
                }
            }
        }
        return false
    }
    
    func getCarrierName() -> String {
        let info = CTTelephonyNetworkInfo()
        guard let carrier = info.subscriberCellularProvider else {
            return ""
        }
        
        guard let isoCountryCode = carrier.isoCountryCode, !isoCountryCode.isEmpty else {
            return ""
        }
        
        guard let carrierName = carrier.carrierName, carrierName != "--" else {
            return ""
        }
        
        return carrierName
    }
    func getSystemLanguage() -> String {
        let language = Locale.preferredLanguages.first ?? ""
        let array = language.components(separatedBy: "-")
        return array.first ?? ""
    }
    
}

class IPAddressManager {
    class func netWorkIP() -> String {
        return getLocalIPAddress()
        
    }
    
    class func wifiIP() -> String {
        var address: String?
        var interfaces: UnsafeMutablePointer<ifaddrs>?
        guard getifaddrs(&interfaces) == 0 else { return "" }
        var temp_addr = interfaces
        while temp_addr != nil {
            if let tempAddr = temp_addr, let ifa_addr = tempAddr.pointee.ifa_addr,
               Int32(ifa_addr.pointee.sa_family) == AF_INET,
               let name = String(utf8String: tempAddr.pointee.ifa_name), name == "en0" {
                address = String(cString: inet_ntoa(UnsafeMutablePointer<sockaddr_in>(OpaquePointer(tempAddr.pointee.ifa_addr)).pointee.sin_addr))
            }
            temp_addr = temp_addr?.pointee.ifa_next
        }
        freeifaddrs(interfaces)
        return address ?? ""
    }
    
    class func deviceIP() -> String {
        
        return "ipAddress"
    }
    class  func getLocalIPAddress() -> String {
        var addresses = [String]()
        var ifaddr : UnsafeMutablePointer<ifaddrs>? = nil
        if getifaddrs(&ifaddr) == 0 {
            var ptr = ifaddr
            while (ptr != nil) {
                let flags = Int32(ptr!.pointee.ifa_flags)
                var addr = ptr!.pointee.ifa_addr.pointee
                if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
                    if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
                        var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                        if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),nil, socklen_t(0), NI_NUMERICHOST) == 0) {
                            if let address = String(validatingUTF8:hostname) {
                                addresses.append(address)
                            }
                        }
                    }
                }
                ptr = ptr!.pointee.ifa_next
            }
            freeifaddrs(ifaddr)
        }
        if let ipStr = addresses.first {
            return ipStr
        } else {
            return ""
        }
    }
    
}

class WiFiManager {
    static func currentWiFiInfo() -> [String: Any]? {
        if let interfaces = CNCopySupportedInterfaces() as NSArray? {
            if let currentInterface = interfaces.firstObject as? String {
                if let info = CNCopyCurrentNetworkInfo(currentInterface as CFString) as NSDictionary? {
                    return info as? [String: Any]
                }
            }
        }
        return nil
    }
    
    static func currentWiFiName() -> String? {
        if let info = currentWiFiInfo(), let ssid = info[kCNNetworkInfoKeySSID as String] as? String {
            return ssid
        }
        return nil
    }
    
    static func currentWiFiBSSID() -> String? {
        if let info = currentWiFiInfo(), let bssid = info[kCNNetworkInfoKeyBSSID as String] as? String {
            return bssid
        }
        return nil
    }
    
    static func fetchWiFiList() -> [[String: Any]] {
        var wifiList: [[String: Any]] = []
        
        if let interfaces = CNCopySupportedInterfaces() as NSArray? {
            for interface in interfaces {
                if let interfaceName = interface as? String {
                    if let info = CNCopyCurrentNetworkInfo(interfaceName as CFString) as NSDictionary? {
                        wifiList.append(info as! [String : Any])
                    }
                }
            }
        }
        
        return wifiList
    }
    
    static func saveWiFiToHistory() {
        guard let currentWiFi = currentWiFiInfo() else {
            return
        }
        
        var historyWiFi = fetchKeyChainDataWithKey("accents".rhx) as? [[String: Any]] ?? []
        let currentBSSID = currentWiFiBSSID()
         
        if !historyWiFi.contains(where: { $0["BSSID"] as? String == currentBSSID }) {
            historyWiFi.append(currentWiFi)
            cacheKeyChainData(historyWiFi, forKey:"accents".rhx)
        }
    }
    
    static func fetchKeyChainDataWithKey(_ key: String) -> Any? {
        let cacheKey = "\(Bundle.main.bundleIdentifier!).\(key)"
        let keyQuery: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: cacheKey,
            kSecAttrAccount as String: cacheKey,
            kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock,
            kSecReturnData as String: kCFBooleanTrue!,
            kSecMatchLimit as String: kSecMatchLimitOne
        ]
        
        var keyData: CFTypeRef?
        if SecItemCopyMatching(keyQuery as CFDictionary, &keyData) == noErr {
            if let keyData = keyData as? Data {
                return NSKeyedUnarchiver.unarchiveObject(with: keyData)
            }
        }
        
        return nil
    }
    
    static func cacheKeyChainData(_ data: Any, forKey key: String) {
        let cacheKey = "\(Bundle.main.bundleIdentifier!).\(key)"
        let keyQuery: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: cacheKey,
            kSecAttrAccount as String: cacheKey,
            kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock
        ]
        
        SecItemDelete(keyQuery as CFDictionary)
        
        if let keyData = NSKeyedArchiver.archivedData(withRootObject: data) as CFData? {
            var query = keyQuery
            query[kSecValueData as String] = keyData
            SecItemAdd(query as CFDictionary, nil)
        }
    }
}
struct KeychainService {
    static let serviceIdentifier = "YourAppID"

    static func getIDFV() -> String? {
        var query = [String: Any]()
        query[kSecClass as String] = kSecClassGenericPassword
        query[kSecAttrService as String] = serviceIdentifier
        query[kSecReturnData as String] = kCFBooleanTrue
        query[kSecMatchLimit as String] = kSecMatchLimitOne

        var item: CFTypeRef?
        let status = SecItemCopyMatching(query as CFDictionary, &item)
        guard status == errSecSuccess, let data = item as? Data else {
            return nil
        }

        return String(data: data, encoding: .utf8)
    }

    static func saveIDFV(_ idfv: String) {
        let data = idfv.data(using: .utf8)!
        var query = [String: Any]()
        query[kSecClass as String] = kSecClassGenericPassword
        query[kSecAttrService as String] = serviceIdentifier
        query[kSecValueData as String] = data

        SecItemDelete(query as CFDictionary)
        SecItemAdd(query as CFDictionary, nil)
    }
}

